﻿using System;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Validation;
using K9Nano.Admin.Weixin.Dto;
using K9Nano.Share.Exceptions;
using Microsoft.Extensions.Logging;

namespace K9Nano.Admin.Weixin.OAuth
{
    /// <summary>
    /// 扩展IdentityServer4的认证方式，支持微信公众号认证
    /// </summary>
    public class WeiXinOpenGrantValidator : IExtensionGrantValidator
    {
        private readonly ILogger _logger;
        private readonly IWeixinAppService _weixinAppService;
        private readonly IWeixinTokenCodeCache _weixinTokenCodeCache;

        public WeiXinOpenGrantValidator(ILogger<WeiXinOpenGrantValidator> logger, IWeixinAppService weixinAppService, IWeixinTokenCodeCache weixinTokenCodeCache)
        {
            _logger = logger;
            _weixinAppService = weixinAppService;
            _weixinTokenCodeCache = weixinTokenCodeCache;
        }

        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            try
            {
                var code = context.Request.Raw["code"];
                var tokenCode = _weixinTokenCodeCache.Get(code);
                if (tokenCode == null)
                {
                    _logger.LogWarning("微信公众号认证失败，本地Code无效：" + code);
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest);
                    return;
                }

                if (context.Request.ClientId != tokenCode.ClientId)
                {
                    _logger.LogWarning("微信公众号认证失败，Code对应的ClientId与请求的ClientId不一致");
                    context.Result = new GrantValidationResult(TokenRequestErrors.UnauthorizedClient);
                    return;
                }

                var model = new WeixinMpLoginModel
                {
                    ClientId = context.Request.ClientId,
                    AppId = tokenCode.AppId,
                    OpenId = tokenCode.OpenId,
                    UnionId = tokenCode.UnionId
                };

                var ticket = await _weixinAppService.WeixinAuthenticateAsync(model, default);

                if (ticket != null)
                {
                    context.Result = new GrantValidationResult(ticket.Principal);
                }
                else
                {
                    // 未绑定微信
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "unbound");
                }
            }
            catch (K9AuthorizationException ex)
            {
                _logger.LogWarning(ex, "微信公众号认证失败");
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "微信公众号认证失败");
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest);
            }
        }

        public string GrantType => Share.K9SharedConstants.GrantTypeWeixinMP;
    }
}